import Utils from "../../../Utils";
import DestructibleFacility from "../../facility/DestructibleFacility";
import LaunchableFalicity from "../../facility/LaunchableFalicity";
import { Killer } from "../../funcObj/interface/HealthPoint";
import { FacilityType, GamePropType } from "../../info/GameEnum";
import { Global } from "../../info/Global";
import { Location, MapLength } from "../../info/Predefine";
import GameManager from "../../manager/GameManager";
import TerrainManager from "../../manager/TerrainManager";
import DestructibleFlyer from "../DestructibleFlyer";

const { ccclass, property } = cc._decorator;
/**
 * 飞弹类 
 * 控制飞弹如何飞行
 */
@ccclass
export default abstract class FlyerMissile extends DestructibleFlyer {

    @property({
        type: cc.Float,
        displayName: "发射前的准备时间"
    })
    readyTime: number = 0.8;

    @property({
        type: cc.Integer,
        displayName: "发射后的升空高度"
    })
    altitude: number = 0;

    @property({
        type: cc.Integer,
        displayName: "爆炸后获得视野半径"
    })
    viewRadius: number = 1;

    @property({
        type: cc.Integer,
        displayName: "爆炸后波及半径"
    })
    blastRadius: number = 0;

    /**
     * 拖尾
     */
    @property(cc.Animation)
    tail: cc.Animation = null;

    /**
     *目标 
     */
    target: cc.Vec3

    /**
     * 升空完成
     */
    liftoff: boolean;

    /**
     * 飞弹攻击力
     */
    atk: number;

    base: LaunchableFalicity;
    /**
     * 转弯速度
     */
    turnSpeed: number;

    public get angle(): number {
        return this.node.angle;
    }

    public set angle(v: number) {
        this.node.angle = v;
    }

    public get moveSpeed(): number {
        let result = this.flyerInfo.移动速度;
        if (GamePropType.超音速) {
            result = Math.ceil(result * 1.5);
        }
        return result;
    }

    init(base: DestructibleFacility, target?: Location): void {
        super.init(base, target);
        let rate = Global.FacilityInfo[FacilityType.主基地].炮弹攻击.每等级加成[this.player.shellDamageBonusLevel] / 100;
        this.atk = Math.ceil(this.flyerInfo.攻击力 + rate * this.flyerInfo.攻击力);
        this.viewRadius = this.flyerInfo.爆炸后获得视野半径 + this.player.extraView;
        this.blastRadius = this.flyerInfo.爆炸后波及半径;
        this.liftoff = false;
        this.turnSpeed = 0;
        this.moveComp.moveSpeed = this.moveSpeed / 2
        this.moveComp.clamp = false;
        if (target) {
            this.dispatch(target);
        }
    }

    initHp(): void {
        super.initHp();
        let rate = Global.FacilityInfo[FacilityType.主基地].炮弹血量.每等级加成[this.player.shellHealthBonusLevel] / 100;
        this.maxHp = this.maxHp + Math.ceil(this.maxHp * rate);
        this.currentHp = this.maxHp;
    }

    dispatch(target: Location) {
        this.target = GameManager.instance.getGamePosition(target);
        this.target.x = Utils.getRandom(this.target.x - 39, this.target.x + 39);
        this.target.y = Utils.getRandom(this.target.y - 39, this.target.y + 39);

        let dis = this.target.sub(this.node.position).mag();
        let altitude = this.altitude;
        if (dis < 400) {
            altitude *= 2;
        }
        let up = this.node.position.add(cc.v3(0, altitude));
        let targetAngle = this.getTargetAngel();
        if (targetAngle > 180) this.angle = 360;
        this.preDispatch();
        this.scheduleOnce(() => {
            this.moveComp.setTarget(up, () => {
                this.liftoff = true;
                this.moveComp.moveSpeed = this.moveSpeed;
                this.collider.enabled = true;
                this.afterLiftoff();
                this.dispatchSuccess(0);
            });
        }, this.readyTime);
    }

    /**
     * 发射前
     */
    protected preDispatch() {
        if (this.tail) {
            this.tail.play();
        }
    }

    /**
     * 升空后
     */
    protected afterLiftoff() {

    }

    onArrive(): void {
        //获得附近的视野
        let location = GameManager.instance.getMapLocation(this.node.position),
            leftUp: Location = { locationX: Math.max(0, location.locationX - this.viewRadius), locationY: Math.max(0, location.locationY - this.viewRadius) },
            rightDown: Location = { locationX: Math.min(MapLength - 1, location.locationX + this.viewRadius), locationY: Math.min(MapLength - 1, location.locationY + this.viewRadius) };

        for (let i = leftUp.locationX; i <= rightDown.locationX; i++) {
            for (let j = leftUp.locationY; j <= rightDown.locationY; j++) {
                this.player.getLocationView({ locationX: i, locationY: j })
            }
        }

        //造成伤害
        leftUp = { locationX: Math.max(0, location.locationX - this.blastRadius), locationY: Math.max(0, location.locationY - this.blastRadius) };
        rightDown = { locationX: Math.min(location.locationX + this.blastRadius, MapLength - 1), locationY: Math.min(location.locationY + this.blastRadius, MapLength - 1) };

        for (let x = leftUp.locationX; x <= rightDown.locationX; x++) {
            for (let y = leftUp.locationY; y <= rightDown.locationY; y++) {
                let tempLocation = { locationX: x, locationY: y };
                let targetFac = GameManager.instance.getFacilityByLocation(tempLocation);
                let radisDis = Math.max(Math.abs(x - location.locationX), Math.abs(y - location.locationY));
                let atk = Math.round(this.atk * Math.pow(0.9, radisDis));
                if (targetFac && targetFac instanceof DestructibleFacility && targetFac.player !== this.player) {
                    targetFac.reducedHp({ flyer: this, facility: this.base, player: this.player, domage: atk });
                    GameManager.instance.addFlyerExploadEffect(this.flyerType, tempLocation, cc.size(80, 80))
                }
                targetFac = GameManager.instance.getFacilityByLocation(tempLocation);
                if ((!targetFac || targetFac.facilityType == FacilityType.安家点) && atk > 0) {
                    TerrainManager.instance.bombardment(tempLocation);
                }
            }
        }
        //回收
        super.onArrive();
    }

    /**
     * 获得需要朝向的角度
     * @returns 
     */
    private getTargetAngel(): number {
        let thisPosition = this.node.position;
        let direction = cc.v2(this.target.x - thisPosition.x, this.target.y - thisPosition.y);
        let targetAngle = cc.misc.radiansToDegrees(cc.Vec2.angle(direction, cc.v2(0, 1)));
        targetAngle = direction.x > 0 ? 360 - targetAngle : targetAngle;
        return targetAngle;
    }

    protected update(dt: number): void {
        if (!this.liftoff) return
        let targetAngle = this.getTargetAngel();
        if (targetAngle - this.angle > 180) {
            this.angle += 360;
        }
        if (this.angle - targetAngle > 180) {
            this.angle -= 360;
        }

        this.turnSpeed += dt;
        let turnSpeed = this.turnSpeed * 200
        let dir = targetAngle > this.angle ? 1 : -1
        let dis = targetAngle - this.angle;
        let angleStep = turnSpeed * dt;
        let next: number = this.angle + angleStep * dir;

        if (Math.abs(dis) > angleStep) {
            this.angle = next;
            this.moveComp.setDirection(Utils.angleToVectorCustom(this.angle));
        } else {
            this.angle = targetAngle;
            this.liftoff = false;
            this.moveComp.setTarget(this.target, this.onArrive.bind(this));
        }
    }

    die(killer: Killer): void {
        if (this.tail) {
            this.tail.stop();
            this.tail.getComponent(cc.Sprite).spriteFrame = null;
        }
        this.angle = 0;
        super.die(killer);
    }

}